package barchecker

import (
	"fmt"
	"strconv"
	"strings"
	"time"
)

func Check(lastTime, currentTime time.Time, exchange, period string) (time.Time, bool) {
	if len(period) == 0 || lastTime.IsZero() {
		return currentTime, true
	}

	exchange = strings.ToUpper(exchange)

	switch {
	case period[len(period)-1] == 'm':
		return checkMinute(lastTime, currentTime, exchange, period)
	case period != "month" && period[len(period)-1] == 'h':
		return checkHour(lastTime, currentTime, exchange, period)
	case period == "day":
		return checkDay(lastTime, currentTime)
	case period == "week":
		return checkWeek(lastTime, currentTime)
	case period == "month":
		return checkMonth(lastTime, currentTime)
	case period == "quarter":
		return checkQuarter(lastTime, currentTime)
	case period == "year":
		return checkYear(lastTime, currentTime)
	default:
		return currentTime, true
	}
}

func checkMinute(lastTime, currentTime time.Time, exchange, period string) (time.Time, bool) {
	minute, err := strconv.Atoi(period[:len(period)-1])
	if err != nil || minute <= 0 {
		return currentTime, false
	}
	if minute%60 == 0 {
		return checkHour(lastTime, currentTime, exchange, fmt.Sprintf("%dh", minute/60))
	}

	intervalSeconds := int64(minute * 60)
	currentBarTimestamp := currentTime.Unix() / intervalSeconds * intervalSeconds

	barTime := time.Unix(currentBarTimestamp+intervalSeconds, 0)

	return barTime, lastTime != barTime
}

func checkHour(lastTime, currentTime time.Time, exchange, period string) (time.Time, bool) {
	hour, err := strconv.Atoi(period[:len(period)-1])
	if err != nil || hour <= 0 || (hour != 1 && hour != 2) {
		return currentTime, false
	}

	if exchange == "SH" || exchange == "SZ" {
		intervalSeconds := int64(hour * 3600)
		y, m, d := currentTime.Date()

		baseTimestamp := time.Date(y, m, d, 9, 30, 0, 0, currentTime.Location()).Unix()
		if currentTime.Hour() >= 13 {
			baseTimestamp = time.Date(y, m, d, 13, 0, 0, 0, currentTime.Location()).Unix()
		}
		// 相对于13点的偏移秒数
		elapsed := currentTime.Unix() - baseTimestamp
		// 向上对齐
		nextInterval := ((elapsed-1)/intervalSeconds + 1) * intervalSeconds

		barTime := time.Unix(baseTimestamp+nextInterval, 0).In(currentTime.Location())
		return barTime, !barTime.Equal(lastTime)

	}

	intervalSeconds := int64(hour * 3600)
	currentBarTimestamp := (currentTime.Unix() + intervalSeconds + 1) / intervalSeconds * intervalSeconds
	lastBarTimestamp := lastTime.Unix() / intervalSeconds * intervalSeconds

	barTime := time.Unix(currentBarTimestamp, 0)
	return barTime, currentBarTimestamp != lastBarTimestamp
}

func checkDay(lastTime, currentTime time.Time) (time.Time, bool) {
	lastYear, lastMonth, lastDay := lastTime.Date()
	currentYear, currentMonth, currentDay := currentTime.Date()

	currentDayStart := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, currentTime.Location())

	return currentDayStart, lastYear != currentYear || lastMonth != currentMonth || lastDay != currentDay
}

func checkWeek(lastTime, currentTime time.Time) (time.Time, bool) {
	lastYear, lastWeek := lastTime.ISOWeek()
	currentYear, currentWeek := currentTime.ISOWeek()

	year, month, day := currentTime.Date()

	return time.Date(year, month, day, 0, 0, 0, 0, currentTime.Location()), lastYear != currentYear || lastWeek != currentWeek
}

func checkMonth(lastTime, currentTime time.Time) (time.Time, bool) {
	lastYear, lastMonth, _ := lastTime.Date()
	currentYear, currentMonth, currentDay := currentTime.Date()

	currentDayStart := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, currentTime.Location())
	return currentDayStart, lastYear != currentYear || lastMonth != currentMonth
}

func checkQuarter(lastTime, currentTime time.Time) (time.Time, bool) {
	lastQuarter := getQuarterStart(lastTime)
	currentQuarter := getQuarterStart(currentTime)

	return currentQuarter, !lastQuarter.Equal(currentQuarter)
}

func checkYear(lastTime, currentTime time.Time) (time.Time, bool) {
	currentYear, currentMonth, currentDay := currentTime.Date()
	currentDayStart := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, currentTime.Location())
	return currentDayStart, lastTime.Year() != currentYear
}

func getQuarterStart(t time.Time) time.Time {
	quarter := (int(t.Month()) - 1) / 3
	quarterStartMonth := time.Month(quarter*3 + 1)
	return time.Date(t.Year(), quarterStartMonth, 1, 0, 0, 0, 0, t.Location())
}
